// SPDX-FileCopyrightText: Adam Evyčędo
//
// SPDX-License-Identifier: AGPL-3.0-or-later

package server

import (
	"strings"

	"apiote.xyz/p/szczanieckiej/api"
	"apiote.xyz/p/szczanieckiej/config"
	"apiote.xyz/p/szczanieckiej/traffic"

	"errors"
	"net/http"

	"apiote.xyz/p/gott/v2"
	"git.sr.ht/~sircmpwn/go-bare"
)

type LineHandlerVars struct {
	HandlerVars

	context traffic.Context

	line traffic.Line
}

func checkLinePath(v AbstractHandlerVars) error {
	if len(v.getPath()) < 3 {
		return ServerError{
			code:  http.StatusNotFound,
			field: "line",
			value: "EMPTY",
		}
	}

	return nil
}

func getLine(v AbstractHandlerVars) (AbstractHandlerVars, error) {
	vv := v.(*LineHandlerVars)
	var (
		line traffic.Line
		err  error
	)
	lineInQuery := v.getRequest().Form.Get("line")
	if lineInQuery != "" {
		line, err = traffic.GetLine(lineInQuery, v.getContext(), v.getTraffic())
	} else {
		lineName := strings.Join(v.getPath()[2:], "/")
		line, err = traffic.GetLineOld(lineName, v.getContext(), v.getTraffic())
	}
	vv.line = line
	return vv, err
}

func checkEmptyLine(v AbstractHandlerVars) error {
	vv := v.(*LineHandlerVars)
	if vv.line.Name == "" {
		return ServerError{
			code:  http.StatusNotFound,
			field: "line",
			value: v.getPath()[2],
		}
	}

	return nil
}

func makeLineResponse(v AbstractHandlerVars) (AbstractHandlerVars, error) {
	vv := v.(*LineHandlerVars)

	response, err := api.MakeLineResponse(vv.line, v.getContext(), v.getTraffic(), v.getAccept())
	v.setResponse(response)
	if err != nil && errors.Is(err, api.AcceptError) {
		err = ServerError{
			code: http.StatusNotAcceptable,
		}
	}

	return vv, err
}

func marshalLineResponse(v AbstractHandlerVars) (AbstractHandlerVars, error) {
	r := v.getResponse().(api.LineResponse)
	bytes, err := bare.Marshal(&r)
	v.setResponseBytes(bytes)
	return v, err
}

func handleLine(w http.ResponseWriter, r *http.Request, feedName string, cfg config.Config, t *traffic.Traffic, accept map[uint]struct{}) error {
	handlerVars := &LineHandlerVars{
		HandlerVars: HandlerVars{
			w: w,
			r: r,
			t: t,
			c: cfg,
			a: accept,
			f: feedName,
		},
	}
	result := gott.R[AbstractHandlerVars]{
		S: handlerVars,
	}
	result = result.
		Bind(splitPath).
		SafeTee(prepareForm).
		Tee(checkLinePath).
		Bind(getVersionCode).
		Map(createContext).
		Bind(getLine).
		Tee(checkEmptyLine).
		Bind(makeLineResponse).
		Bind(marshalLineResponse).
		Tee(writeResponse)

	return result.E
}
